package net.oschina.arvin.sqlbuilder;

import net.oschina.arvin.sqlbuilder.definition.ColumnDefinition;
import net.oschina.arvin.sqlbuilder.utils.AssertUtil;
import net.oschina.arvin.sqlbuilder.utils.ReflectUtil;
import net.oschina.arvin.sqlbuilder.utils.Util;

import java.util.Date;
import java.util.List;

/**
 * 插入语句构建器
 *
 * @author Arvin
 * @time 2017/11/16 14:08
 */
public class InsertBuilder extends AbstractNotQueryBuilder<InsertBuilder> {

    public static final String INSERT_INTO_PREFIX = "INSERT INTO ";
    public static final String REPLACE_INTO_PREFIX = "REPLACE INTO ";

    /** 要处理的模型对象 */
    private final Object model;

    public InsertBuilder(Object model) {
        super(model.getClass(), SqlBuilderType.INSERT);

        this.model = model;
    }

    @Override
    protected InsertBuilder self() {
        return this;
    }

    @Override
    protected String build() {

        StringBuilder builder = new StringBuilder(getWrapTablename());
        StringBuilder fieldsBuilder = new StringBuilder("(");
        StringBuilder valuesBuilder = new StringBuilder(" VALUES(");

        List<ColumnDefinition> columnDefinitionList = getColumnDefinitionList();

        for (ColumnDefinition columnDefinition : columnDefinitionList) {
            if (columnDefinition.isPrimaryKey()) {
                appendPrimaryKeyColumn(fieldsBuilder, valuesBuilder, columnDefinition);
            } else if (columnDefinition.isUniqueKey()) {
                appendUniqueKeyColumn(fieldsBuilder, valuesBuilder, columnDefinition);
            } else {
                appendNormalColumn(fieldsBuilder, valuesBuilder, columnDefinition);
            }
        }
        fieldsBuilder.setLength(fieldsBuilder.length() - 1);
        fieldsBuilder.append(")");

        valuesBuilder.setLength(valuesBuilder.length() - 1);
        valuesBuilder.append(")");

        builder.append(fieldsBuilder.toString()).append(valuesBuilder.toString());

        return builder.toString();
    }

    private void appendNormalColumn(StringBuilder fieldsBuilder, StringBuilder valuesBuilder, ColumnDefinition columnDefinition) {
        if (!columnDefinition.isInsertIgnore()) {
            // 不忽略的情况下进行处理
            Object columnValue = ReflectUtil.getFieldValue(model, columnDefinition.getField());

            if (columnDefinition.isUseCurrentTimeWhenAdd()) {
                if (columnValue == null) {
                    columnValue = Util.createCurrentTimeByTimeType(columnDefinition.getFieldType());
                    ReflectUtil.setFieldValue(model, columnDefinition.getField(), columnValue);
                }
            }

            AssertUtil.assertFalse(null == columnValue && columnDefinition.isNotNull(), "字段[" + columnDefinition.getFieldName() + "]不允许为null！");

            appendColumn(fieldsBuilder, valuesBuilder, columnDefinition, columnValue);
        }
    }

    private void appendUniqueKeyColumn(StringBuilder fieldsBuilder, StringBuilder valuesBuilder, ColumnDefinition columnDefinition) {
        appendNormalColumn(fieldsBuilder, valuesBuilder, columnDefinition);
    }

    /**
     * 添加主键
     *
     * @param fieldsBuilder    属性构建器
     * @param valuesBuilder    值构建器
     * @param columnDefinition 列定义
     */
    private void appendPrimaryKeyColumn(StringBuilder fieldsBuilder, StringBuilder valuesBuilder, ColumnDefinition columnDefinition) {
        Object pkValue = ReflectUtil.getFieldValue(model, columnDefinition.getField());

        if (columnDefinition.isCanAutoIncrement() && columnDefinition.isAutoIncrement()) {
            // 自增的，检查一下是否有大于0， 大于0 的话就需要添加到语句中， 否则直接忽略
            if (isNumberPkValueOverZero(pkValue)) {
                appendColumn(fieldsBuilder, valuesBuilder, columnDefinition, pkValue);
            }
            return;
        } else if (columnDefinition.isCanUseUuid() && columnDefinition.isUseUuid()) {
            if (!isValidUuid(pkValue)) {
                pkValue = Util.generateUUID();
                ReflectUtil.setFieldValue(model, columnDefinition.getField(), pkValue);
                appendColumn(fieldsBuilder, valuesBuilder, columnDefinition, pkValue);
            }
            return;
        }

        AssertUtil.assertNotNull(pkValue, "主键值不能为空！");

        appendColumn(fieldsBuilder, valuesBuilder, columnDefinition, pkValue);
    }

    private void appendColumn(StringBuilder fieldsBuilder, StringBuilder valuesBuilder, ColumnDefinition columnDefinition, Object columnValue) {

        if (null == columnValue) {
            columnValue = columnDefinition.getDefaultValue();
            if (columnValue == null && !columnDefinition.isInsertIncludeNull()) {
                return;
            }
        }
        if (null == columnValue) {
            valuesBuilder.append("null,");
        } else {
            valuesBuilder.append("?,");
            addParamByColumnDefinition(columnDefinition, columnValue);
        }

        fieldsBuilder.append(columnDefinition.getWrapColumnName()).append(",");
    }

    private boolean isValidUuid(Object pkValue) {
        if (null == pkValue) {
            return false;
        }

        return Util.isNotBlank(String.valueOf(pkValue));
    }

    private boolean isNumberPkValueOverZero(Object pkValue) {

        if (null == pkValue) {
            return false;
        }

        try {
            return Long.valueOf(String.valueOf(pkValue)) > 0;
        } catch (NumberFormatException e) {
            return false;
        }
    }

    /**
     * 默认返回Insert语句
     *
     * @return 修改原有逻辑为默认返回INSERT INTO
     */
    @Override
    public String getSql() {
        return INSERT_INTO_PREFIX + super.getSql();
    }

    /**
     * 获取Insert语句
     *
     * @return 返回Insert语句
     */
    public String getInsertSql() {
        String sql = INSERT_INTO_PREFIX + super.getSql();
        logUsedSql(sql);
        return sql;
    }

    /**
     * 获取 REPLACE INTO 语句
     *
     * @return 返回 REPLACE INTO 语句
     */
    public String getReplaceIntoSql() {
        String sql = REPLACE_INTO_PREFIX + super.getSql();
        logUsedSql(sql);
        return sql;
    }
}
